home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Contrib / PythonScript / baepack.py next >
Encoding:
Python Source  |  2000-06-23  |  10.7 KB  |  386 lines

  1. """Tools for use in AppleEvent clients and servers:
  2. conversion between AE types and python types
  3.  
  4. pack(x) converts a Python object to an AEDesc object
  5. unpack(desc) does the reverse
  6. coerce(x, wanted_sample) coerces a python object to another python object
  7. """
  8.  
  9. #
  10. # This code was originally written by Guido, and modified/extended by Jack
  11. # to include the various types that were missing. The reference used is
  12. # Apple Event Registry, chapter 9.
  13. #
  14.  
  15. import struct
  16. import string
  17. import types
  18. from string import strip
  19. from types import *
  20. import AE
  21. from AppleEvents import *
  22. from AERegistry import *
  23. from AEObjects import *
  24. import MacOS
  25. import macfs
  26. import StringIO
  27. import baetypes
  28. from baetypes import mkenum, mktype
  29.  
  30. import calldll
  31.  
  32. OSL = calldll.getlibrary('ObjectSupportLib')
  33.  
  34. # These ones seem to be missing from AppleEvents
  35. # (they're in AERegistry.h)
  36.  
  37. #typeColorTable = 'clrt'
  38. #typeDrawingArea = 'cdrw'
  39. #typePixelMap = 'cpix'
  40. #typePixelMapMinus = 'tpmm'
  41. #typeRotation = 'trot'
  42. #typeTextStyles = 'tsty'
  43. #typeStyledText = 'STXT'
  44. #typeAEText = 'tTXT'
  45. #typeEnumeration = 'enum'
  46.  
  47. #
  48. # Some AE types are immedeately coerced into something
  49. # we like better (and which is equivalent)
  50. #
  51. unpacker_coercions = {
  52.     typeComp : typeExtended,
  53.     typeColorTable : typeAEList,
  54.     typeDrawingArea : typeAERecord,
  55.     typeFixed : typeExtended,
  56.     typeFloat : typeExtended,
  57.     typePixelMap : typeAERecord,
  58.     typeRotation : typeAERecord,
  59.     typeStyledText : typeAERecord,
  60.     typeTextStyles : typeAERecord,
  61. };
  62.  
  63. #
  64. # Some python types we need in the packer:
  65. #
  66. AEDescType = type(AE.AECreateDesc('TEXT', ''))
  67. _sample_fss = macfs.FSSpec(':')
  68. _sample_alias = _sample_fss.NewAliasMinimal()
  69. FSSType = type(_sample_fss)
  70. AliasType = type(_sample_alias)
  71.  
  72. def pack(x, forcetype = None):
  73.     """Pack a python object into an AE descriptor"""
  74. #    print 'aepack', x, type(x), forcetype
  75. #    if type(x) == TupleType:
  76. #        forcetype, x = x
  77.     if forcetype:
  78.         print x, forcetype
  79.         if type(x) is StringType:
  80.             return AE.AECreateDesc(forcetype, x)
  81.         else:
  82.             return pack(x).AECoerceDesc(forcetype)
  83.             
  84.     if x == None:
  85.         return AE.AECreateDesc('null', '')
  86.         
  87.     t = type(x)
  88.     if t == AEDescType:
  89.         return x
  90.     if t == FSSType:
  91.         return AE.AECreateDesc('fss ', x.data)
  92.     if t == AliasType:
  93.         return AE.AECreateDesc('alis', x.data)
  94.     if t == IntType:
  95.         return AE.AECreateDesc('long', struct.pack('l', x))
  96.     if t == FloatType:
  97.         #
  98.         # XXXX (note by Guido) Weird thing -- Think C's "double" is 10 bytes, but
  99.         # struct.pack('d') return 12 bytes (and struct.unpack requires
  100.         # them, too).  The first 2 bytes seem to be repeated...
  101.         # Probably an alignment problem
  102.         # XXXX (note by Jack) haven't checked this under MW
  103.         #
  104. #        return AE.AECreateDesc('exte', struct.pack('d', x)[2:])
  105.         return AE.AECreateDesc('exte', struct.pack('d', x))
  106.     if t == StringType:
  107.         return AE.AECreateDesc('TEXT', x)
  108.     if t == ListType:
  109.         list = AE.AECreateList('', 0)
  110.         for item in x:
  111.             list.AEPutDesc(0, pack(item))
  112.         return list
  113.     if t == DictionaryType:
  114.         record = AE.AECreateList('', 1)
  115.         for key, value in x.items():
  116.             record.AEPutParamDesc(key, pack(value))
  117.         return record
  118.     if t == InstanceType and hasattr(x, '__aepack__'):
  119.         return x.__aepack__()
  120.     return AE.AECreateDesc('TEXT', repr(x)) # Copout
  121.  
  122. def unpack(desc):
  123.     """Unpack an AE descriptor to a python object"""
  124.     t = desc.type
  125. #    print t
  126.     
  127.     if unpacker_coercions.has_key(t):
  128.         desc = desc.AECoerceDesc(unpacker_coercions[t])
  129.         t = desc.type # This is a guess by Jack....
  130.     
  131.     if t == typeAEList:
  132.         l = []
  133.         for i in range(desc.AECountItems()):
  134.             keyword, item = desc.AEGetNthDesc(i+1, '****')
  135.             l.append(unpack(item))
  136.         return l
  137.     if t == typeAERecord:
  138.         d = {}
  139.         for i in range(desc.AECountItems()):
  140.             keyword, item = desc.AEGetNthDesc(i+1, '****')
  141.             d[keyword] = unpack(item)
  142.         return d
  143.     if t == typeAEText:
  144.         record = desc.AECoerceDesc('reco')
  145.         return mkaetext(unpack(record))
  146.     if t == typeAlias:
  147.         return macfs.RawAlias(desc.data)
  148.     # typeAppleEvent returned as unknown
  149.     if t == typeBoolean:
  150.         return struct.unpack('b', desc.data)[0]
  151.     if t == typeChar:
  152.         return desc.data
  153.     # typeColorTable coerced to typeAEList
  154.     # typeComp coerced to extended
  155.     # typeData returned as unknown
  156.     # typeDrawingArea coerced to typeAERecord
  157.     if t == typeEnumeration:
  158.         return mkenum(desc.data)
  159.     # typeEPS returned as unknown
  160.     if t == typeExtended:
  161. #        print desc, type(desc), len(desc)
  162.         data = desc.data
  163. #        print `data[:8]`, type(data), len(data[:8])
  164. #        print struct.unpack('=d', data[:8])[0]
  165. #        print string.atoi(data), type(data), len(data)
  166. #        print struct.calcsize(data)
  167.         # XXX See corresponding note for pack()
  168. #        return struct.unpack('d', data[:2] + data)[0]
  169.         return struct.unpack('d', data[:8])[0]
  170.     if t == typeFalse:
  171.         return 0
  172.     # typeFixed coerced to extended
  173.     # typeFloat coerced to extended
  174.     if t == typeFSS:
  175.         return macfs.RawFSSpec(desc.data)
  176.     if t == typeInsertionLoc:
  177.         record = desc.AECoerceDesc('reco')
  178.         return mkinsertionloc(unpack(record))
  179.     # typeInteger equal to typeLongInteger
  180.     if t == typeIntlText:
  181.         script, language = struct.unpack('hh', desc.data[:4])
  182.         return baetypes.IntlText(script, language, desc.data[4:])
  183.     if t == typeIntlWritingCode:
  184.         script, language = struct.unpack('hh', desc.data)
  185.         return baetypes.IntlWritingCode(script, language)
  186.     if t == typeKeyword:
  187.         return mkkeyword(desc.data)
  188.     # typeLongFloat is equal to typeFloat
  189.     if t == typeLongInteger:
  190. #        print t, struct.unpack('l', desc.data)
  191.         return struct.unpack('l', desc.data)[0]
  192.     if t == typeNull:
  193.         return None
  194.     if t == typeMagnitude:
  195.         v = struct.unpack('l', desc.data)
  196.         if v < 0:
  197.             v = 0x100000000L + v
  198.         return v
  199.     if t == typeObjectSpecifier:
  200.         import Res
  201. #        print desc, type(desc)
  202. #        print desc.__members__
  203. #        print desc.data, desc.type
  204. #        print unpack(desc)
  205. #        getOSL = calldll.newcall(OSL.AEResolve, 'OSErr', 'InHandle', 'InShort')#, 'InString')
  206. #        print 'OSL', getOSL(rdesc, 0)#, desc.data)
  207.         record = desc.AECoerceDesc('reco')
  208. #        print record
  209.         return mkobject(unpack(record))
  210.     # typePict returned as unknown
  211.     # typePixelMap coerced to typeAERecord
  212.     # typePixelMapMinus returned as unknown
  213.     # typeProcessSerialNumber returned as unknown
  214.     if t == typeQDPoint:
  215.         v, h = struct.unpack('hh', desc.data)
  216.         return baetypes.QDPoint(v, h)
  217.     if t == typeQDRectangle:
  218.         v0, h0, v1, h1 = struct.unpack('hhhh', desc.data)
  219.         return baetypes.QDRectangle(v0, h0, v1, h1)
  220.     if t == typeRGBColor:
  221.         r, g, b = struct.unpack('hhh', desc.data)
  222.         return baetypes.RGBColor(r, g, b)
  223.     # typeRotation coerced to typeAERecord
  224.     # typeScrapStyles returned as unknown
  225.     # typeSessionID returned as unknown
  226.     if t == typeShortFloat:
  227.         return struct.unpack('f', desc.data)[0]
  228.     if t == typeShortInteger:
  229. #        print t, desc.data
  230. #        print struct.unpack('h', desc.data)[0]
  231.         return struct.unpack('h', desc.data)[0]
  232.     # typeSMFloat identical to typeShortFloat
  233.     # typeSMInt    indetical to typeShortInt
  234.     # typeStyledText coerced to typeAERecord
  235.     if t == typeTargetID:
  236.         return mktargetid(desc.data)
  237.     # typeTextStyles coerced to typeAERecord
  238.     # typeTIFF returned as unknown
  239.     if t == typeTrue:
  240.         return 1
  241.     if t == typeType:
  242. #        print t, desc.data
  243.         return mktype(desc.data)
  244.     #
  245.     # The following are special
  246.     #
  247.     if t == 'rang':
  248.         record = desc.AECoerceDesc('reco')
  249.         return mkrange(unpack(record))
  250.     if t == 'cmpd':
  251.         record = desc.AECoerceDesc('reco')
  252.         return mkcomparison(unpack(record))
  253.     if t == 'logi':
  254.         record = desc.AECoerceDesc('reco')
  255.         return mklogical(unpack(record))
  256.     return mkunknown(desc.type, desc.data)
  257.     
  258. def coerce(data, egdata):
  259.     """Coerce a python object to another type using the AE coercers"""
  260.     pdata = pack(data)
  261.     pegdata = pack(egdata)
  262.     pdata = pdata.AECoerceDesc(pegdata.type)
  263.     return unpack(pdata)
  264.  
  265. #
  266. # Helper routines for unpack
  267. #
  268. def mktargetid(data):
  269.     sessionID = getlong(data[:4])
  270.     name = mkppcportrec(data[4:4+72])
  271.     location = mklocationnamerec(data[76:76+36])
  272.     rcvrName = mkppcportrec(data[112:112+72])
  273.     return sessionID, name, location, rcvrName
  274.  
  275. def mkppcportrec(rec):
  276.     namescript = getword(rec[:2])
  277.     name = getpstr(rec[2:2+33])
  278.     portkind = getword(rec[36:38])
  279.     if portkind == 1:
  280.         ctor = rec[38:42]
  281.         type = rec[42:46]
  282.         identity = (ctor, type)
  283.     else:
  284.         identity = getpstr(rec[38:38+33])
  285.     return namescript, name, portkind, identity
  286.  
  287. def mklocationnamerec(rec):
  288.     kind = getword(rec[:2])
  289.     stuff = rec[2:]
  290.     if kind == 0: stuff = None
  291.     if kind == 2: stuff = getpstr(stuff)
  292.     return kind, stuff
  293.  
  294. def mkunknown(type, data):
  295.     return baetypes.Unknown(type, data)
  296.  
  297. def getpstr(s):
  298.     return s[1:1+ord(s[0])]
  299.  
  300. def getlong(s):
  301.     return (ord(s[0])<<24) | (ord(s[1])<<16) | (ord(s[2])<<8) | ord(s[3])
  302.  
  303. def getword(s):
  304.     return (ord(s[0])<<8) | (ord(s[1])<<0)
  305.  
  306. def mkkeyword(keyword):
  307.     return baetypes.Keyword(keyword)
  308.  
  309. def mkrange(dict):
  310.     return baetypes.Range(dict['star'], dict['stop'])
  311.  
  312. def mkcomparison(dict):
  313.     return baetypes.Comparison(dict['obj1'], dict['relo'].enum, dict['obj2'])
  314.  
  315. def mklogical(dict):
  316.     return baetypes.Logical(dict['logc'], dict['term'])
  317.  
  318. def mkstyledtext(dict):
  319.     return baetypes.StyledText(dict['ksty'], dict['ktxt'])
  320.     
  321. def mkaetext(dict):
  322.     return baetypes.AEText(dict[keyAEScriptTag], dict[keyAEStyles], dict[keyAEText])
  323.     
  324. def mkinsertionloc(dict):
  325.     return baetypes.InsertionLoc(dict[keyAEObject], dict[keyAEPosition])
  326.  
  327. def mkobject(dict):
  328.     want = dict['want'].type
  329.     form = dict['form'].enum
  330.     seld = dict['seld']
  331.     fr   = dict['from']
  332.     if form in ('name', 'indx', 'rang', 'test'):
  333.         if want == 'text': return baetypes.Text(seld, fr)
  334.         if want == 'cha ': return baetypes.Character(seld, fr)
  335.         if want == 'cwor': return baetypes.Word(seld, fr)
  336.         if want == 'clin': return baetypes.Line(seld, fr)
  337.         if want == 'cpar': return baetypes.Paragraph(seld, fr)
  338.         if want == 'cwin': return baetypes.Window(seld, fr)
  339.         if want == 'docu': return baetypes.Document(seld, fr)
  340.         if want == 'file': return baetypes.File(seld, fr)
  341.         if want == 'cins': return baetypes.InsertionPoint(seld, fr)
  342.     if want == 'prop' and form == 'prop' and baetypes.IsType(seld):
  343.         return baetypes.Property(seld.type, fr)
  344.     return baetypes.ObjectSpecifier(want, form, seld, fr)
  345.  
  346. def _test():
  347.     """Test program. Pack and unpack various things"""
  348.     objs = [
  349.         'a string',
  350.         12,
  351.         12.0,
  352.         None,
  353.         ['a', 'list', 'of', 'strings'],
  354.         {'key1': 'value1', 'key2':'value2'},
  355.         macfs.FSSpec(':'),
  356.         macfs.FSSpec(':').NewAliasMinimal(),
  357.         baetypes.Enum('enum'),
  358.         baetypes.Type('type'),
  359.         baetypes.Keyword('kwrd'),
  360.         baetypes.Range(1, 10),
  361.         baetypes.Comparison(1, '<   ', 10),
  362.         baetypes.Logical('not ', 1),
  363.         # Cannot do StyledText
  364.         # Cannot do AEText
  365.         baetypes.IntlText(0, 0, 'international text'),
  366.         baetypes.IntlWritingCode(0,0),
  367.         baetypes.QDPoint(50,100),
  368.         baetypes.QDRectangle(50,100,150,200),
  369.         baetypes.RGBColor(0x7000, 0x6000, 0x5000),
  370.         baetypes.Unknown('xxxx', 'unknown type data'),
  371.         baetypes.Character(1),
  372.         baetypes.Character(2, baetypes.Line(2)),
  373.     ]
  374.     for o in objs:
  375.         print 'BEFORE', o, `o`
  376.         print type(o)
  377.         packed = pack(o)
  378.         unpacked = unpack(packed)
  379.         print 'AFTER ', unpacked, `unpacked`
  380.     import sys
  381.     sys.exit(1)
  382.     
  383. if __name__ == '__main__':
  384.     _test()
  385.     
  386.